package cn.zeal4j.configuration;

import cn.zeal4j.handler.CustomAccessDeniedHandler;
import cn.zeal4j.handler.FarsAuthenticationFailureHandler;
import cn.zeal4j.handler.FarsAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.parameters.P;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @author Administrator
 * @file IntelliJ IDEA Spring-Security-Tutorial
 * @create 2020 09 27 21:55
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    @Qualifier("userDetailsServiceImpl")
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource); // 数据源注入
        jdbcTokenRepository.setCreateTableOnStartup(false); // 由Security完成Token表的创建，如果有了就设置false关闭
        return jdbcTokenRepository;
    }

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.formLogin(). // 设置登陆行为方式为表单登陆
                // 登陆请求参数设置
                usernameParameter("username").
                passwordParameter("password").

                // loginPage("/login.html"). // 设置登陆页面URL路径
                loginPage("/csrf-login.page").
                loginProcessingUrl("/login.action"). // 设置表单提交URL路径

                successForwardUrl("/main.page"). // 设置认证成功跳转URL路径 POST请求
                failureForwardUrl("/error.page");  // 设置认证失败跳转URL路径 POST请求

                //  successHandler(new FarsAuthenticationSuccessHandler("https://www.acfun.cn/")). // 使用自定义的重定向登陆
                //  failureHandler(new FarsAuthenticationFailureHandler("/error.html")).; // 跨域处理，不需要跳转了

        httpSecurity.authorizeRequests().
                regexMatchers(HttpMethod.POST, "正则表达式").permitAll(). // 还可以对符合正则表达式的请求方式进行要求，这个属性使用来制定请求的方式

                antMatchers("/**/*.js", "/**/*.css", "/**/images/*.*").permitAll(). // 静态资源放行

                antMatchers("/csrf-login.page").permitAll().
                antMatchers("/login.html").permitAll(). // 登陆页面允许任意访问
                antMatchers("/error.html").permitAll(). // 失败跳转后重定向的页面也需要被允许访问
                antMatchers("/admin.page").hasAnyAuthority("admin").

                /*antMatchers("/vip-01.page").hasAnyAuthority("vip-01").*/
                antMatchers("/vip-01.page").hasRole("vip-01").
                antMatchers("/ip.page").hasIpAddress("192.168.43.180").

                // mvcMatchers("/main.page").servletPath("/xxx").permitAll(). // mvcMatchers资源放行匹配
                // antMatchers("/xxx/main.page").permitAll(). // 或者多写MSP的前缀

                anyRequest().authenticated(); // 其他请求均需要被授权访问
                // anyRequest().access("@customServiceImpl.hasPermission(request, authentication)"); // 自定义Access配置

        // CSRF攻击拦截关闭
        // httpSecurity.csrf().disable();

        httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler);


        // 记住我
        httpSecurity.rememberMe().
                tokenValiditySeconds(60). // 设置Token有效时间， 以秒为单位取值
                userDetailsService(userDetailsService).
                tokenRepository(persistentTokenRepository);

        // 退出登录处理
        httpSecurity.
                logout().
                // logoutUrl("/xxx/xxx/logout").
                logoutSuccessUrl("/login.html");
    }
}
